<?php

namespace App\Services;

use Dcat\Admin\Admin;
use Exception;
use App\Models\Config;
use Illuminate\Support\Facades\Mail;

class WuKongImService
{

    private $config = [];
    private $batch = "/route/batch";//获取一批用户的连接地址
    private $useraddress = '/route?uid=';//获取客户端连接悟空 IM的地址
    private $send = '/message/send';//发送消息
    private $register = '/user/token';//将用户信息注册到悟空 IM，如果存在则更新
    private $channelinfo = '/channel/messagesync';//获取某个频道的消息列表
    private $syncmessage = '/conversation/sync';//客户端离线后每次进来需要同步一次最近会话（包含离线的最新的消息）
    private $setUnread = '/conversations/setUnread';//设置某个频道的最近会话未读消息数量
    private $channelMessageDelete = '/conversations/delete';//删除某个频道的最近会话
    private $createChannel = '/channel';//创建频道
    private $delChannel = '/channel/delete';//删除一个频道（注意：如果配置了datasource记得不要返回删除了频道的数据，要不然重启又会恢复回来）
    private $addSubscribers = '/channel/subscriber_add';//向一个已存在的频道内添加订阅者
    private $removeSubscribers = '/channel/subscriber_remove';//向一个已存在的频道内移除订阅者
    private $findUsersStatus = '/user/onlinestatus';//查询一批用户的在线状态。
    private $systemuidsAdd = '/user/systemuids_add';//系统账号将有发送消息的全部权限，不受黑名单限制，无需在订阅列表里，比如“系统通知”，“客服”等这种类似账号可以设置系统账号
    private $systemuidsRemove = '/user/systemuids_remove';//将系统账号移除
    private $device_quit = '/user/device_quit';//将用户的设备踢出登录，（可以实现类似微信的 app 可以踢出 pc 登录）

    /**
     * @throws Exception
     */
    public function __construct()
    {
        $this->config = config("wukong");
        if (empty($this->config)) {
            throw new Exception('IM配置错误');
        }
    }

    public static function getChannelId()
    {
        return config('wukong.channel_id');
    }

    /**
     * 获取http请求地址
     * @param string $url
     * @param string|null $parameter
     * @param string $url
     * @param string|null $parameter
     * @return string
     *
     * @return string
     */
    public function getHttpClientUrl(string $url, string $parameter = null)
    {
        if (empty($parameter)) {
            $url = 'http://' . $this->config['addr'] . ':' . $this->config['apiport'] . $url;
        } else {
            $url = 'http://' . $this->config['addr'] . ':' . $this->config['apiport'] . $url . $parameter;
        }
        return $url;
    }

    /**
     * 获取一批用户连接地址
     * @return array|int[]|mixed
     */
    public function getBatch()
    {
        $url = $this->getHttpClientUrl($this->useraddress, '11');
        try {
            $response = \Illuminate\Support\Facades\Http::get($url);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            return [222];
        }
    }

    /**
     * 发送消息
     * @param $uid
     * @param $touid
     * @param $message
     * @param int $channel_type 接收频道类型  1.个人频道 2.群聊频道
     * @return array|mixed
     * @throws Exception
     */
    public function sendTo($uid, $touid, $message, int $channel_type = 1)
    {
        $url = $this->getHttpClientUrl($this->send);
        $messagedata = base64_encode(json_encode(['type' => 1, 'content' => $message]));
        $data = [
            'header' => [
                'no_persist' => 0,// 是否不存储消息 0.存储 1.不存储
                'red_dot' => 1,// 是否显示红点计数，0.不显示 1.显示
                'sync_once' => 0 // 是否是写扩散，这里一般是0，只有cmd消息才是1
            ],
            'from_uid' => $uid, // 发送者uid
            'stream_no' => '',// 流式消息编号，如果是流式消息，需要指定，否则为空
            'channel_id' => $touid,// 接收频道ID 如果channel_type=1 channel_id为个人uid 如果channel_type=2 channel_id为群id
            'channel_type' => $channel_type,// 接收频道类型  1.个人频道 2.群聊频道
            'payload' => $messagedata,// 消息内容，base64编码
            'subscribers' => []  // 订阅者 如果此字段有值，表示消息只发给指定的订阅者,没有值则发给频道内所有订阅者
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, ($data));
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 注册用户
     * @param $uid
     * @param $token
     * @return array|mixed
     * @throws Exception
     */
    public function reg($uid, $token)
    {
        $url = $this->getHttpClientUrl($this->register);
        $data = [
            'uid' => $uid,
            'token' => $token,
            'device_flag' => 1,
            'device_level' => 1
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 获取频道消息
     * @param $uid 当前登录用户uid
     * @param $channel_id 频道ID
     * @return array|mixed
     * @throws Exception
     */
    public function getChannelInfo($uid, $channel_id)
    {
        $url = $this->getHttpClientUrl($this->channelinfo);
        $data = [
            'login_uid' => $uid,// 当前登录用户uid
            'channel_id' => $channel_id,//  频道ID
            'channel_type' => 1,// 频道类型
            'start_message_seq' => 0,// 开始消息列号（结果包含start_message_seq的消息）
            'end_message_seq' => 0,// 结束消息列号（结果不包含end_message_seq的消息）
            'limit' => 100,// 消息数量限制
            'pull_mode' => 1// 拉取模式 0:向下拉取 1:向上拉取
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    public function syncMessages($uid)
    {
        $url = $this->getHttpClientUrl($this->syncmessage);
        $data = [
            'uid' => $uid, // 当前登录用户uid
            'version' => 0,//  当前客户端的会话最大版本号(从保存的结果里取最大的version，如果本地没有数据则传0)，
            'last_msg_seqs' => '',//   客户端所有频道会话的最后一条消息序列号拼接出来的同步串 格式： channelID:channelType:last_msg_seq|channelID:channelType:last_msg_seq  （此字段非必填，如果不填就获取全量数据，填写了获取增量数据，看你自己的需求。）
            'msg_count' => 20// 每个会话获取最大的消息数量，一般为app点进去第一屏的数据
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 设置未读消息数量
     * @param $uid 当前登录用户uid
     * @param $channel_id 频道ID
     * @param $unread 未读消息数量
     * @return array|mixed
     * @throws Exception
     */
    public function setUnread($uid, $channel_id, $unread = 0)
    {
        $url = $this->getHttpClientUrl($this->setUnread);
        $data = [
            'uid' => $uid, // 当前登录用户uid
            'channel_id' => $channel_id,//  频道ID
            'channel_type' => 1,// 频道类型
            'unread' => $unread// 未读消息数量
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 频道消息删除
     * @param $uid 当前登录用户uid
     * @param $channel_id 频道ID
     * @return array|mixed
     * @throws Exception
     */
    public function channelMessageDelete($uid, $channel_id)
    {
        $url = $this->getHttpClientUrl($this->channelMessageDelete);
        $data = [
            'uid' => $uid, // 当前登录用户uid
            'channel_id' => $channel_id,//  频道ID
            'channel_type' => 1,// 频道类型
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 创建频道
     * @param $channel_id  频道的唯一ID，如果是群聊频道，建议使用群聊ID
     * @return array|mixed
     * @throws Exception
     */
    public function createChannel($channel_id)
    {
        $url = $this->getHttpClientUrl($this->createChannel);
        $data = [
            'channel_id' => $channel_id,//  // 频道的唯一ID，如果是群聊频道，建议使用群聊ID
            'channel_type' => 2,// // 频道的类型 1.个人频道 2.群聊频道（个人与个人聊天不需要创建频道，系统将自动创建）
            'large' => 0,// 是否是超大群，0.否 1.是 （一般建议500成员以上设置为超大群，注意：超大群不会维护最近会话数据。）
            'ban' => 0,// 是否封禁此频道，0.否 1.是 （被封后 任何人都不能发消息，包括创建者）
            'subscribers' => [],// 订阅者集合
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 删除频道
     * @param $channel_id
     * @return array|mixed
     * @throws Exception
     */
    public function delChannel($channel_id)
    {
        $url = $this->getHttpClientUrl($this->delChannel);
        $data = [
            'channel_id' => $channel_id,//  // 频道的唯一ID，如果是群聊频道，建议使用群聊ID
            'channel_type' => 2,// // 频道的类型 1.个人频道 2.群聊频道（个人与个人聊天不需要创建频道，系统将自动创建）
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 添加订阅者
     * @param $channel_id
     * @param array $subscribers 订阅者集合
     * @param int $reset 是否重置订阅者 （0.不重置 1.重置），选择重置，则删除旧的订阅者，选择不重置则保留旧的订阅者
     * @param int $temp_subscriber 是否为临时频道 0.否 1.是 临时频道的订阅者将在下次重启后自动删除
     * @return array|mixed
     * @throws Exception
     */
    public function addSubscribers($channel_id, array $subscribers, $reset = 0, $temp_subscriber = 0)
    {
        $url = $this->getHttpClientUrl($this->addSubscribers);
//        dd($url);
        $data = [
            'channel_id' => $channel_id,//  // 频道的唯一ID，如果是群聊频道，建议使用群聊ID
            'channel_type' => 2,// // 频道的类型 1.个人频道 2.群聊频道（个人与个人聊天不需要创建频道，系统将自动创建）
            'reset' => $reset, // 是否重置订阅者 （0.不重置 1.重置），选择重置，则删除旧的订阅者，选择不重置则保留旧的订阅者
            'subscribers' => $subscribers,//订阅者集合
            'temp_subscriber' => $temp_subscriber,//是否为临时频道 0.否 1.是 临时频道的订阅者将在下次重启后自动删除
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 移除订阅者
     * @param $channel_id
     * @param array $subscribers 订阅者集合
     * @return array|mixed
     * @throws Exception
     */
    public function removeSubscribers($channel_id, array $subscribers)
    {
        $url = $this->getHttpClientUrl($this->removeSubscribers);
        $data = [
            'channel_id' => $channel_id,//  // 频道的唯一ID，如果是群聊频道，建议使用群聊ID
            'channel_type' => 2,// // 频道的类型 1.个人频道 2.群聊频道（个人与个人聊天不需要创建频道，系统将自动创建）
            'subscribers' => $subscribers,//订阅者集合
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 查询一批用户的在线状态
     * @param array $uids
     * @return array|mixed
     * @throws Exception
     */
    public function findUsersStatus(array $uids = [])
    {
        $url = $this->getHttpClientUrl($this->findUsersStatus);
        $data = $uids;
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 添加系统账号
     * @param array $uids
     * @return array|mixed
     * @throws Exception
     */
    public function systemuidsAdd(array $uids = [])
    {
        $url = $this->getHttpClientUrl($this->systemuidsAdd);
        $data = ['uids' => $uids];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 移除系统账号
     * @param array $uids
     * @return array|mixed
     * @throws Exception
     */
    public function systemuidsRemove(array $uids = [])
    {
        $url = $this->getHttpClientUrl($this->systemuidsRemove);
        $data = ['uids' => $uids];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 踢出用户的设备登录
     * @param string $uid
     * @param int $device_flag 需要踢出的设备标记 -1: 当前用户下所有设备 0： 当前用户下的app 1： 当前用户下的web 2： 当前用户下的pc
     * @return array|mixed
     * @throws Exception
     */
    public function deviceQuit(string $uid, int $device_flag = 0)
    {
        $url = $this->getHttpClientUrl($this->device_quit);
        $data = [
            'uid' => $uid,
            'device_flag' => $device_flag,// 需要踢出的设备标记 -1: 当前用户下所有设备 0： 当前用户下的app 1： 当前用户下的web 2： 当前用户下的pc
        ];
        try {
            $response = \Illuminate\Support\Facades\Http::post($url, $data);
            $data = $response->json();
            if ($response->status() == 200) {
                return $data;
            } else {
                throw new Exception($data['message']);
            }
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

}
